-- Combat.lua — CLEU parsing robuste + routage vers DFFT.showNumber
local ADDON, DFFT = ...
-- Ne PAS retourner ici : on veut enregistrer les slash-cmds même si DFFT/DB n'est pas encore prêt.
local DB = DFFT and DFFT.DB or nil

-- Par défaut: debug icônes OFF (si la DB existe déjà très tôt)
if DB and DB.iconDebug == nil then DB.iconDebug = false end

-- ====== état local ======
local playerGUID, petGUID

-- ====== util DB ======
local function safeDB()
  return (DFFT and DFFT.DB) or DB or {}
end

-- ====== util icône (compatible retail/classic) ======
local FALLBACK_ICON = "Interface\\Icons\\INV_Misc_QuestionMark"

-- Retourne le chemin/ID d'icône pour un spellID si possible, sinon nil.
local function SpellIcon(spellId)
  if not spellId then return nil end
  if C_Spell and C_Spell.GetSpellInfo then
    local info = C_Spell.GetSpellInfo(spellId)
    if info and info.iconID then return info.iconID end
  end
  if _G.GetSpellTexture then
    local tex = _G.GetSpellTexture(spellId)
    if tex then return tex end
  end
  if _G.GetSpellInfo then
    local _, _, icon = _G.GetSpellInfo(spellId)
    if icon then return icon end
  end
  return nil
end

-- ====== util source/target ======
local function isFromPlayerOrPet(srcGUID)
  if not srcGUID then return false end
  if srcGUID == playerGUID then return true end
  local sdb = safeDB()
  if sdb.includePet and petGUID and srcGUID == petGUID then return true end
  return false
end

local function isOwnerTarget(dstGUID)
  local tGUID = UnitGUID and UnitGUID("target")
  return (tGUID ~= nil and dstGUID ~= nil and tGUID == dstGUID)
end

-- Renvoie amount, isCrit, spellId (si dispo)
local function extractAmountCritSpell(sub, ...)
  if sub == "SWING_DAMAGE" then
    local amount, _, _, _, _, _, critical = ...
    return tonumber(amount) or 0, not not critical, nil
  elseif sub == "RANGE_DAMAGE" or sub == "SPELL_DAMAGE" then
    local spellId, _, _, amount, _, _, _, _, _, critical = ...
    return tonumber(amount) or 0, not not critical, spellId
  elseif sub == "SPELL_PERIODIC_DAMAGE" or sub == "DAMAGE_SPLIT" or sub == "DAMAGE_SHIELD" then
    local spellId, _, _, amount, _, _, _, _, _, critical = ...
    return tonumber(amount) or 0, not not critical, spellId
  end
  return 0, false, nil
end

-- ====== affichage dégâts ======
local function handleAmount(sub, srcGUID, dstGUID, ...)
  local sdb = safeDB()
  if not DFFT then return end

  local amount, isCrit, spellId = extractAmountCritSpell(sub, ...)
  if amount <= 0 then return end
  if not isFromPlayerOrPet(srcGUID) then return end

  if sdb.autoThresholds and DFFT.Auto_OnNewAmount then
    DFFT.Auto_OnNewAmount(amount)
  end

  local smallMax  = sdb.smallMax or 0
  local bigMin    = math.max(sdb.bigMin or 0, smallMax + 1)
  local vbigMin   = math.max(sdb.veryBigMin or 0, bigMin + 1)

  local onTarget = isOwnerTarget(dstGUID)

  -- Toujours passer/stasher l'icône; TextFrames décidera d'afficher (showIcons) ou non
  local icon = spellId and SpellIcon(spellId) or nil
  local opts = icon and { icon = icon } or nil
  if icon then DFFT._iconForNext = icon end -- STASH de secours
  if sdb.iconDebug then
    print(("[SCT 战斗] %s 法术=%s 图标=%s 选项=%s"):format(tostring(sub), tostring(spellId), tostring(icon), opts and "是" or "否"))
  end

  local text
  if amount <= smallMax then
    if sdb.showSmall == false then return end
    text = (DFFT.shortNumberRounded and DFFT.shortNumberRounded(amount)) or tostring(amount)
    if DFFT.showNumber then DFFT.showNumber(amount, text, "small", onTarget, isCrit, nil, opts) end
  elseif amount < bigMin then
    if sdb.showMedium == false then return end
    text = (DFFT.shortNumberRounded and DFFT.shortNumberRounded(amount)) or tostring(amount)
    if DFFT.showNumber then DFFT.showNumber(amount, text, "medium", onTarget, isCrit, nil, opts) end
  elseif amount >= vbigMin then
    text = (DFFT.shortNumber and DFFT.shortNumber(amount)) or tostring(amount)
    if DFFT.showNumber then DFFT.showNumber(amount, text, "vbig", onTarget, isCrit, nil, opts) end
  else
    text = (DFFT.shortNumber and DFFT.shortNumber(amount)) or tostring(amount)
    if DFFT.showNumber then DFFT.showNumber(amount, text, "big", onTarget, isCrit, nil, opts) end
  end
end

-- ====== libellés MISS (anglais) ======
local MISS_LABELS = {
  MISS    = "未命中",
  DODGE   = "躲闪",
  PARRY   = "招架",
  EVADE   = "闪避",
  IMMUNE  = "免疫",
  BLOCK   = "格挡",
  ABSORB  = "吸收",
  REFLECT = "反射",
  RESIST  = "抵抗",
  DEFLECT = "偏转",
}
local MISS_ORDER = { "MISS","DODGE","PARRY","EVADE","IMMUNE","BLOCK","ABSORB","REFLECT","RESIST","DEFLECT" }

-- ====== affichage MISS ======
local function handleMiss(sub, srcGUID, dstGUID, ...)
  if not DFFT then return end
  if not isFromPlayerOrPet(srcGUID) then return end

  local missType, amountMissed, spellId
  if sub == "SWING_MISSED" then
    local mt, _, amt = ...
    missType = mt
    amountMissed = tonumber(amt)
  else
    local sid, _, _, mt, _, amt = ...
    spellId = sid
    missType = mt
    amountMissed = tonumber(amt)
  end

  local key  = tostring(missType or "")
  local base = MISS_LABELS[key] or "Miss"

  local label
  if (key == "ABSORB" or key == "BLOCK" or key == "RESIST") and amountMissed and amountMissed > 0 then
    local shortAmt = (DFFT.shortNumberRounded and DFFT.shortNumberRounded(amountMissed)) or tostring(amountMissed)
    label = base .. " (" .. shortAmt .. ")"
  else
    label = base
  end

  local onTarget = isOwnerTarget(dstGUID)

  -- icône optionnelle
  local icon = (spellId and SpellIcon(spellId)) or nil
  local opts = icon and { icon = icon } or nil
  if icon then DFFT._iconForNext = icon end -- STASH de secours
  if safeDB().iconDebug then
    print(("[SCT 战斗] %s 法术=%s 图标=%s 选项=%s"):format(tostring(sub), tostring(spellId), tostring(icon), opts and "是" or "否"))
  end

  if DFFT.showNumber then
    DFFT.showNumber(0, label, onTarget and "medium" or "small", onTarget, false, nil, opts)
  end
end

-- ====== Events ======
local dmgEvents = {
  SWING_DAMAGE = true, RANGE_DAMAGE = true, SPELL_DAMAGE = true,
  SPELL_PERIODIC_DAMAGE = true, DAMAGE_SPLIT = true, DAMAGE_SHIELD = true,
}
local missEvents = {
  SWING_MISSED = true, RANGE_MISSED = true, SPELL_MISSED = true,
}

local f = CreateFrame("Frame")
f:SetScript("OnEvent", function(_, event, ...)
  if event == "PLAYER_LOGIN" or event == "PLAYER_ENTERING_WORLD" then
    playerGUID = UnitGUID and UnitGUID("player")
    petGUID    = UnitGUID and UnitGUID("pet")
    if DFFT and DFFT.DB then
      DB = DFFT.DB
      -- Par défaut: debug icônes OFF (seconde barrière quand la DB est certaine d'exister)
      if DB.iconDebug == nil then DB.iconDebug = false end
    end
  elseif event == "UNIT_PET" then
    local unit = ...
    if unit == "player" then petGUID = UnitGUID and UnitGUID("pet") end
  elseif event == "COMBAT_LOG_EVENT_UNFILTERED" then
    local ts, sub, hideCaster,
      srcGUID, srcName, srcFlags, srcRaidFlags,
      dstGUID, dstName, dstFlags, dstRaidFlags = CombatLogGetCurrentEventInfo()

    if dmgEvents[sub] then
      handleAmount(sub, srcGUID, dstGUID, select(12, CombatLogGetCurrentEventInfo()))
    elseif missEvents[sub] then
      handleMiss(sub, srcGUID, dstGUID, select(12, CombatLogGetCurrentEventInfo()))
    end
  end
end)

f:RegisterEvent("PLAYER_LOGIN")
f:RegisterEvent("PLAYER_ENTERING_WORLD")
f:RegisterEvent("UNIT_PET")
f:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")

-- ====== Commandes de test ======

-- 1) /sctmiss : tests “Miss - Dodge - Block (X)…” avec montant optionnel
SLASH_SCTMISSTEST1 = "/sctmiss"
SlashCmdList.SCTMISSTEST = function(msg)
  local raw = (msg or ""):gsub("^%s+", ""):gsub("%s+$", "")
  local m = raw:lower()

  local function showLabel(label)
    if DFFT and DFFT.showNumber then
      DFFT.showNumber(0, label, "medium", true, false)
    else
      print("|cFF77FF77Sleek Combat Text:|r "..label)
    end
  end

  if m == "" then
    for i, key in ipairs(MISS_ORDER) do
      local label = MISS_LABELS[key]
      C_Timer.After(0.15 * (i - 1), function() showLabel(label) end)
    end
    print("|cFF77FF77Sleek Combat Text:|r 未命中测试 (连发)。")
    return
  end

  local word, rest = m:match("^(%S+)%s*(.*)$")
  local map = {
    miss="MISS", dodge="DODGE", parry="PARRY", evade="EVADE", immune="IMMUNE",
    block="BLOCK", absorb="ABSORB", reflect="REFLECT", resist="RESIST", deflect="DEFLECT",
  }
  local key = map[word or ""]
  if not key then
    print("|cFFFF7777Sleek Combat Text:|r 用法: /sctmiss [未命中|躲闪|招架|闪避|免疫|格挡|吸收|反射|抵抗|偏转] [数值]")
    return
  end

  local num = rest and rest:match("[-+]?%d+%.?%d*")
  local amount = num and tonumber(num) or nil

  local label = MISS_LABELS[key]
  if (key == "ABSORB" or key == "BLOCK" or key == "RESIST") and amount and amount > 0 then
    local shortAmt = (DFFT and DFFT.shortNumberRounded and DFFT.shortNumberRounded(amount)) or tostring(amount)
    label = label .. " (" .. shortAmt .. ")"
  end

  showLabel(label)
  print("|cFF77FF77Sleek Combat Text:|r test -> "..label)
end

-- 2) /scticons on|off : toggles dans DFFT.DB (pas local)
SLASH_SCTICONS1 = "/scticons"
SlashCmdList.SCTICONS = function(msg)
  local raw = (msg or ""):lower():gsub("^%s+",""):gsub("%s+$","")
  DFFT = DFFT or {}
  DFFT.DB = DFFT.DB or {}
  if raw == "on" or raw == "1" or raw == "true" then
    DFFT.DB.showIcons = true
    print("|cFF55FF55Sleek Combat Text:|r 图标开启")
  elseif raw == "off" or raw == "0" or raw == "false" then
    DFFT.DB.showIcons = false
    print("|cFFFF5555Sleek Combat Text:|r 图标关闭")
  else
    local state = ((DFFT.DB.showIcons) ~= false) and "|cff55ff55ON|r" or "|cffff5555OFF|r"
    print("|cFF77FF77Sleek Combat Text:|r 图标状态为 "..state.."。用法: /scticons on|off")
  end
end

-- 3) /scticon [spellId|path] : test d’icône
SLASH_SCTICON1 = "/scticon"
SlashCmdList.SCTICON = function(msg)
  local raw = (msg or ""):gsub("^%s+", ""):gsub("%s+$", "")

  if raw == "" then
    local demo = {133, 116, 172}
    for i, id in ipairs(demo) do
      local tex = SpellIcon(id) or FALLBACK_ICON
      local label = ("测试图标 %d"):format(i)
      C_Timer.After(0.12*(i-1), function()
        if DFFT and DFFT.showNumber then
          DFFT.showNumber(0, label, "medium", true, false, nil, tex and {icon=tex} or nil)
        end
      end)
    end
    print("|cFF77FF77Sleek Combat Text:|r /scticon - 演示 (3个法术)。")
    return
  end

  local tex
  local id = tonumber(raw:match("^%d+$") or "")
  if id then
    tex = SpellIcon(id) or FALLBACK_ICON
  else
    local path = raw:match("^path%s+(.+)$") or raw
    tex = path
  end

  if DFFT and DFFT.showNumber then
    DFFT.showNumber(0, "Test Icon", "medium", true, false, nil, tex and {icon=tex} or nil)
    print("|cFF55FF55Sleek Combat Text:|r 图标测试成功。(贴图="..tostring(tex)..")")
  end
end

-- 4) /scticondbg [spellId] : diagnostics
SLASH_SCTICONDBG1 = "/scticondbg"
SlashCmdList.SCTICONDBG = function(msg)
  local id = tonumber(msg or "")
  if not id then
    print("|cFF77FF77SCT:|r 用法: /scticondbg <法术ID>")
    return
  end
  local a=nil; if C_Spell and C_Spell.GetSpellInfo then local info=C_Spell.GetSpellInfo(id); a=info and info.iconID end
  local b=nil; if _G.GetSpellTexture then b=_G.GetSpellTexture(id) end
  local c=nil; if _G.GetSpellInfo then local _,_,icon=_G.GetSpellInfo(id); c=icon end
  local pick = SpellIcon(id) or FALLBACK_ICON
  print(("|cFF77FF77SCT 调试:|r ID=%d  C_Spell.iconID=%s  GetSpellTexture=%s  GetSpellInfo.icon=%s  -> 选中=%s"):format(id, tostring(a), tostring(b), tostring(c), tostring(pick)))
  if DFFT and DFFT.showNumber then
    DFFT.showNumber(0, "DBG Icon", "medium", true, false, nil, {icon=pick})
  end
end

-- 5) /scticonraw : force un affichage icône (fileID et fallback)
SLASH_SCTICONRAW1 = "/scticonraw"
SlashCmdList.SCTICONRAW = function(msg)
  local id = tonumber(msg or "") or 135846 -- fileID de Frostbolt d’après tes logs
  local tex = id
  if DFFT and DFFT.showNumber then
    DFFT.showNumber(0, "RAW Icon", "medium", true, false, nil, {icon = tex})
    C_Timer.After(0.15, function()
      DFFT.showNumber(0, "RAW Fallback", "medium", true, false, nil, {icon = FALLBACK_ICON})
    end)
  end
  print("|cFF77FF77SCT:|r /scticonraw -> 尝试文件ID "..id.." 然后回退。")
end

-- 6) /scticonping : vérifie que TON TextFrames.lua (avec icônes) est bien chargé
SLASH_SCTICONPING1 = "/scticonping"
SlashCmdList.SCTICONPING = function()
  local ok = (DFFT and DFFT._supportsIconRing) and "OK" or "MISSING"
  print("|cFF77FF77SCT 测试:|r TextFrames 图标支持 = "..ok)
end

-- ====== Debug icônes (sans /run) ======
local function _sctEnsureDB()
  DFFT = DFFT or {}; DFFT.DB = DFFT.DB or {}
  return DFFT.DB
end

-- /sctidebug on|off  -> active les logs d'icône
SLASH_SCTIDEBUG1 = "/sctidebug"
SlashCmdList.SCTIDEBUG = function(msg)
  local db = _sctEnsureDB()
  local m = (msg or ""):lower():gsub("^%s+",""):gsub("%s+$","")
  if m == "on" or m == "1" or m == "true" then
    db.iconDebug = true
    print("|cFF77FF77SCT:|r 图标调试 = 开启")
  elseif m == "off" or m == "0" or m == "false" then
    db.iconDebug = false
    print("|cFF77FF77SCT:|r 图标调试 = 关闭")
  else
    print("|cFF77FF77SCT:|r 用法: /sctidebug on|off (当前: "..tostring(db.iconDebug)..")")
  end
end

-- /sctiforce on|off -> force un carré magenta au lieu de la texture (diagnostic z-order/pipeline)
SLASH_SCTIFORCE1 = "/sctiforce"
SlashCmdList.SCTIFORCE = function(msg)
  local db = _sctEnsureDB()
  local m = (msg or ""):lower():gsub("^%s+",""):gsub("%s+$","")
  if m == "on" or m == "1" or m == "true" then
    db.iconForceSquare = true
    print("|cFF77FF77SCT:|r 图标强制方形 = 开启 (洋红色)")
  elseif m == "off" or m == "0" or m == "false" then
    db.iconForceSquare = false
    print("|cFF77FF77SCT:|r 图标强制方形 = 关闭")
  else
    print("|cFF77FF77SCT:|r 用法: /sctiforce on|off (当前: "..tostring(db.iconForceSquare)..")")
  end
end

-- /sctivis -> montre 3 essais: fileID, fallback, puis carré magenta (si forcé)
SLASH_SCTIVIS1 = "/sctivis"
SlashCmdList.SCTIVIS = function()
  local db = _sctEnsureDB()
  db.showIcons = true
  db.iconDebug = true
  local fileID = 135846 -- ton Frostbolt (vu dans tes logs)
  local fallback = "Interface\\Icons\\INV_Misc_QuestionMark"

  if DFFT and DFFT.showNumber then
    DFFT.showNumber(0, "可视化文件ID", "medium", true, false, nil, { icon = fileID })
    C_Timer.After(0.15, function()
      DFFT.showNumber(0, "可视化回退", "medium", true, false, nil, { icon = fallback })
    end)
    C_Timer.After(0.30, function()
      db.iconForceSquare = true
      DFFT.showNumber(0, "可视化洋红色", "medium", true, false, nil, { icon = fileID })
      C_Timer.After(0.20, function() db.iconForceSquare = false end)
    end)
  end
  print("|cFF77FF77SCT:|r /sctivis 已启动 (文件ID -> 回退 -> 洋红色)。")
end

-- ====== Diagnostics avancés ======
-- /sctwho : qui parle + derniers opts/icon
SLASH_SCTWHO1 = "/sctwho"
SlashCmdList.SCTWHO = function()
  local okFlag     = DFFT and DFFT._supportsIconRing
  local showPtr    = DFFT and DFFT.showNumber and tostring(DFFT.showNumber) or "nil"
  local savedPtr   = DFFT and DFFT._showNumberPtr or "nil"
  local sawOpts    = DFFT and DFFT._lastSawOpts or "nil"
  local lastIcon   = DFFT and DFFT._lastIconApplied or "nil"
  local db = (DFFT and DFFT.DB) or {}
  print(("|cFF77FF77SCT 信息:|r _supportsIconRing=%s  showNumber=%s  savedPtr=%s  showIcons=%s  iconDebug=%s  sawOpts=%s  lastIcon=%s")
    :format(tostring(okFlag), showPtr, tostring(savedPtr), tostring(db.showIcons~=false), tostring(db.iconDebug), tostring(sawOpts), tostring(lastIcon)))
end

-- /sctblit : carré magenta + ring en overlay (hors pipeline)
SLASH_SCTBLIT1 = "/sctblit"
SlashCmdList.SCTBLIT = function()
  local frame = CreateFrame("Frame", nil, UIParent)
  frame:SetFrameStrata("FULLSCREEN_DIALOG")
  frame:SetFrameLevel(10000)
  frame:SetSize(120, 120)
  frame:SetPoint("CENTER", UIParent, "CENTER", 0, 120)

  local tex = frame:CreateTexture(nil, "OVERLAY")
  tex:SetAllPoints(frame)
  tex:SetColorTexture(1, 0, 1, 0.85)

  local ring = frame:CreateTexture(nil, "OVERLAY")
  ring:SetTexture("Interface\\Buttons\\UI-Quickslot2")
  ring:SetBlendMode("ADD")
  ring:SetVertexColor(1,1,1,1)
  ring:SetPoint("CENTER", frame, "CENTER", 0, 0)
  ring:SetSize(140, 140)

  C_Timer.After(1.5, function() frame:Hide() end)
  print("|cFF77FF77SCT:|r /sctblit -> 显示洋红色+圆环 (1.5秒)。")
end
